﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FCS
{
    #region Foldl<T>

    sealed class Foldl<T> : FunList<T>
    {
        private IFunList<T> List { get; set; }
        private T Identity { get; set; }
        private FunBinary<T> Action { get; set; }

        public Foldl(FunBinary<T> action, T identity, IFunList<T> list)
        {
            List = list;
            Identity = identity;
            Action = action;
        }

        #region IEnumerable<T> Members

        /// <summary>
        /// (define (foldr f z xs)
        ///  (if (null? xs)
        ///   z
        ///   (f (car xs) (foldr f z (cdr xs)))))
        /// </summary>
        /// <returns></returns>
        public override IEnumerator<T> GetEnumerator()
        {
            // simplified implementation for performance reasons
            T tmp = Identity;
            foreach (var v in List)
            {
                tmp = Action(tmp, v);
            }
            yield return tmp;
            //if (List.Count() == 0)
            //{
            //    yield return new Value<T>(Identity);
            //}
            //else
            //{

            //    foreach (var v in new Foldl<T>(Action, Action(Identity, new Head<T>(List).Value), new Tail<T>(List)))
            //    {
            //        yield return v;
            //    }
            //}
        }

        #endregion
    }

    #endregion

    #region Foldr<T>

    sealed class Foldr<T> : FunList<T>
    {
        private IFunList<T> List { get; set; }
        private T Identity { get; set; }
        private FunBinary<T> Action { get; set; }

        public Foldr(FunBinary<T> action, T identity, IFunList<T> list)
        {
            List = list;
            Identity = identity;
            Action = action;
        }

        #region IEnumerable<T> Members

        /// <summary>
        /// (define (foldr f z xs)
        ///  (if (null? xs)
        ///   z
        ///   (f (car xs) (foldr f z (cdr xs)))))
        /// </summary>
        /// <returns></returns>
        public override IEnumerator<T> GetEnumerator()
        {
            // simplified implementation for performance reasons
            T tmp = Identity;
            foreach (var v in List.Reverse())
            {
                tmp = Action(v, tmp);
            }
            yield return tmp;
            //if (List.Count() == 0)
            //{
            //    yield return new Value<T>(Identity);
            //}
            //else
            //{
            //    yield return Action(new Head<T>(List).Value, new Head<T>(new Foldr<T>(Action, Identity, new Tail<T>(List))).Value);
            //}
        }

        #endregion
    }

    #endregion
}
